
/* 异常监控 */
import '@src/util/onerror/reference.js'

import { isElement, isString } from '@src/util/type'
import Clipboard from 'clipboard'



// 公用dom, 使用前请确保清空内容
// 禁止插入文档中，禁止添加或修改属性，如有需要自行创建dom
let tempEl = null;

/** 动态加载一个js, 返回一个Promise */
export function importScript(url) {
  return new Promise(function (resolve, reject) {
    let script = document.createElement('script');
    script.src = url;
    document.body.appendChild(script);

    script.onload = () => resolve();
    script.onerror = error => reject(error);
  });
}

/** 从html创建一个dom */
export function fromHtml(html = '') {
  if (null == tempEl) {
    tempEl = document.createElement('div')
  }

  tempEl.innerHTML = html.trim();
  return tempEl.childNodes[0];
}

/** 获取滚动条的宽度 */
export function getScrollBarWidth() {
  let el = document.createElement('div');

  let styles = {
    width: '100px',
    height: '100px',
    overflowY: 'scroll'
  };

  for (let i in styles) el.style[i] = styles[i];

  document.body.appendChild(el);
  let scrollbarWidth = el.offsetWidth - el.clientWidth;

  document.body.removeChild(el);
  el = null;

  // 下次直接返回结果
  getScrollBarWidth = function () { //eslint-disable-line
    return scrollbarWidth;
  }

  return scrollbarWidth;
}

/** 反转义html */
export function decodeHTML(text) {
  if (null == tempEl) {
    tempEl = document.createElement('div')
  }

  tempEl.innerHTML = text;
  return tempEl.innerText || tempEl.textContent;
}

/** 
 * 将元素全屏
 * 注：frame需要加allowfullscreen属性
 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/requestFullScreen
 */
export function fullScreen(dom) {
  if(!(dom instanceof Element)) return;

  if(dom.requestFullscreen) return dom.requestFullscreen();
  if(dom.webkitRequestFullScreen) return dom.webkitRequestFullScreen();
  if(dom.mozRequestFullScreen) return dom.mozRequestFullScreen();
  if(dom.msRequestFullscreen) return dom.msRequestFullscreen();
  
  return alert('您的浏览器不支持全屏，请升级您的浏览器');
}

/** 销毁组件实例 */
export function destroyComponent(instance){
  try {
    let el = instance.$el;
    let parent = el.parentNode;
    let copyInstance = instance;
    
    copyInstance.$destroy(true);
    copyInstance = null;
    parent && parent.removeChild(el); 
  } catch (error) {
    console.warn(error)
  }
}

/**
 * 用于获取顶层window
 * 顶层window中添加了一个特殊属性[__root_window_],因此判断该属性即可
 * 
 * 注：不适合使用惰性函数改写
 * 
 * @param win - 当前窗口window对象
 */
export function getRootWindow(win) {
  // 非frame 环境
  if(win === window.top) return win;
  
  if(win.__root_window_ == 'root') return win;
  if(win.parent.__root_window_ == 'root') return win.parent;
  
  return getRootWindow(win.parent);
}
// 导入导出按钮是否显示
export function checkButtonDisplayed(){
  const rootWindow = getRootWindow(window)
  // console.log('eventlist', rootWindow._init)
  // console.log('eventlist ~ rootWindow', JSON.parse(rootWindow._init).WHITE_LIST)
  try {
    return JSON.parse(rootWindow._init).WHITE_LIST
  } catch (error) {
    return 0
  }
}

export function hasClass(el, cls) {
  if (!el || !cls) return false;
  if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
  if (el.classList) return el.classList.contains(cls);

  return (` ${ el.className } `).indexOf(` ${ cls } `) > -1;
}

export function trim(string) {
  return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
}

export function removeClass(el, cls) {
  if (!el || !cls) return;
  let classes = cls.split(' ');
  let curClass = ` ${ el.className } `;
  
  for (let i = 0, j = classes.length; i < j; i++) {
    let clsName = classes[i];
    if (!clsName) continue;
    
    if (el.classList) {
      el.classList.remove(clsName);
    } else if (hasClass(el, clsName)) {
      curClass = curClass.replace(` ${ clsName } `, ' ');
    }
  }
  if (!el.classList) {
    el.className = trim(curClass);
  }
}

/**
 * 通过正则表达式移除元素的class
 * @param {Element} el
 * @param {RegExp} regExp 需要移除的class
 */
export function removeClassByRegExp(el, regExp) {
  if (!el || !regExp || !(regExp instanceof RegExp)) return;
  let currClassList = el.classList;
  let resClassList = [];

  if(currClassList.length > 0) {
    currClassList.forEach(className => {
      if(!regExp.test(className)) {
        resClassList.push(className);
      }
    });
  }

  el.classList = resClassList;
}

export function addClass(el, cls) {
  if (!el) return;
  let curClass = el.className;
  let classes = (cls || '').split(' ');
  
  for (let i = 0, j = classes.length; i < j; i++) {
    let clsName = classes[i];
    if (!clsName) continue;
    
    if (el.classList) {
      el.classList.add(clsName);
    } else if (!hasClass(el, clsName)) {
      curClass += ` ${ clsName }`;
    }
  }
  if (!el.classList) {
    el.className = curClass;
  }
}

export function getStyle(el, styleProp) {
  let value, defaultView = (el.ownerDocument || document).defaultView;
  let copyStyleProp = styleProp;
  // W3C standard way:
  if (defaultView && defaultView.getComputedStyle) {
    // sanitize property name to css notation
    // (hyphen separated words eg. font-Size)
    copyStyleProp = copyStyleProp.replace(/([A-Z])/g, '-$1').toLowerCase();
    return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
  } else if (el.currentStyle) { // IE
    // sanitize property name to camelCase
    copyStyleProp = copyStyleProp.replace(/\-(\w)/g, function (str, letter) {
      return letter.toUpperCase();
    });
    value = el.currentStyle[copyStyleProp];
    // convert other units to pixels on IE
    if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
      return (function (value) {
        let oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
        let copyValue = value;
        el.runtimeStyle.left = el.currentStyle.left;
        el.style.left = value || 0;
        copyValue = `${ el.style.pixelLeft }px`;
        el.style.left = oldLeft;
        el.runtimeStyle.left = oldRsLeft;
        return copyValue;
      })(value);
    }
    return value;
  }
}

export function getTextWidth() {
  // do some things...
}

export function createElement(tag, attrs){
  let element = document.createElement(tag);

  if(null != attrs){
    for(let prop in attrs) element[prop] = attrs[prop]
  }

  return element;
}

/**
 * @description 是否为body元素
 * @param {Element} element 元素
 * @return {Boolean}
 */
export function isBodyElement(element) {
  return element.tagName.toLowerCase() === 'body'
}

/**
 * @description 通过类名寻找父级元素
 * -- 另一种方法是通过contains方法判断，不过这个场景下不适用。
 * -- 后续如果有类似的可以使用contains，点击下面👇链接查看
 * @url {@link https://developer.mozilla.org/zh-CN/docs/Web/API/Node/contains}
 * @param {Element} currentNode 当前元素
 * @param {String} className 类名
 * @return {Element | null}
 */
export function findParentElementWithClassName(currentNode, className) {
  if (!isElement(currentNode) || !isString(className)) return null
  
  let parentNode = currentNode.parentNode
  
  if (hasClass(parentNode, className)) {
    return parentNode
  }
  
  if (isBodyElement(parentNode)) {
    return null
  }
  
  return findParentElementWithClassName(parentNode, className)
}

export function setClipboardData(data, successCallback, errorCallback) {
  // 获取body
  let body = document.getElementsByTagName('body')[0];
  
  let copyFrom = document.createElement('a')
  copyFrom.setAttribute('id', 'target')
  copyFrom.setAttribute('target', '_blank')
  copyFrom.setAttribute('href', data)
  copyFrom.innerHTML = data
  
  // 创建按钮
  let agent = document.createElement('button')
  // body增加超链接
  body.appendChild(copyFrom);
  // body增加按钮
  body.appendChild(agent)
  // 采用Clipboard.js方案 // trouble：没有可以传入的HTML元素，但我们可以动态创建一个DOM对象作为代理，复制超链接
  let clipboard = new Clipboard(agent, {
    target() {
      return document.getElementById('target');
    }
  })
  
  clipboard.on('success', function (event) {
    successCallback(event)
  })
  
  clipboard.on('error', function (event) {
    errorCallback()
  })
  
  // 点击按钮
  agent.click()
  // 移除创建的元素
  body.removeChild(copyFrom)
  body.removeChild(agent)
  
}

/** 
 * @description 加载script脚本
 * @param {String} url 脚本地址
 * @return {Promise<boolean} 是否加载成功
*/
export async function loadScript(url) {
  
  return new Promise((resolve, reject) => {
    
    let script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;
    
    script.onload = script.onreadystatechange = function () {
      if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {
        resolve(true)
      }
      
    }
    
    script.onerror = function (error) {
      reject(error)
    }
    
    document.body.appendChild(script);
    
  })
}

function loadCss(url){
  
  const head = document.getElementsByTagName('head').item(0);
  const css = document.createElement('link');
  
  css.href = url;
  css.rel = 'stylesheet';
  css.type = 'text/css';
  
  head && head.appendChild(css);
  
}

/** 表单校验后滚动到第一个必填 */
export async function scrollIntoFirstRequireDom(form) {
  const formBuilderChildren = form.$children.filter(item => !['form-view', 'form-info'].includes(item.$el.className));
  for (let i = 0; i < formBuilderChildren.length; i++) {
    const formBuilderChildrenItem = formBuilderChildren[i];
    if (formBuilderChildrenItem?.$el.classList.contains('err')) {
      formBuilderChildrenItem.$el.scrollIntoView({behavior: 'smooth'});
      break;
    }
  }
}

export {
  loadCss
}
